﻿/*
 * @Author: ws.s 
 * @Date: 2021-10-22 21:46:50 
 * @Last Modified by: ws.s
 * @Last Modified time: 2021-10-22 21:48:22
 */

using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;


/// <summary>
/// 简易对象池，一般作为组件脚本使用的对象池,只能对当局的对象进行回收
/// 2020-11-13 17:48:07  追加，对象池上限设置，超过上限将会无法回收
/// </summary>
[AddComponentMenu("Behavior/EasyPool")]
public class BhvEasyPool : MonoBehaviour
{

    /// <summary>
    /// EasyPool 的回收接口,继承可使用BhvEasyPool回收对象
    /// </summary>
    public interface IPoolRecycle
    {
        /// <summary>
        /// 从对象池取出时触发该方法
        /// </summary>
        void OnRecycleGet();

        /// <summary>
        /// 放入对象池触发该方法
        /// </summary>
        void OnRecyclePut();
    }
    
    public GameObject cloneObject;
    public Stack<GameObject> stack = new Stack<GameObject>();

    public int cacheCount;

    //初始缓存数量, 防止瞬间大量调用的问题
    public int initCacheSize = 5;

    private void Awake()
    {
        if (cloneObject == null)
        {
            cloneObject = transform.GetChild(0).gameObject;
            cloneObject.SetActive(false);
        }

        if (transform.childCount <= initCacheSize)
        {
            for (int i = 0; i < initCacheSize; i++)
            {
                var obj = Instantiate(cloneObject);
                obj.transform.SetParent(transform);
                Put(obj);
            }
        }

    }

    public void Init(GameObject cloneObject, int initCacheSize = 5)
    {
        if (cloneObject == null)
        {
            cloneObject = transform.GetChild(0).gameObject;
            cloneObject.SetActive(false);
        }

        this.initCacheSize = initCacheSize;
        this.cloneObject = cloneObject;

        for (int i = 0; i < initCacheSize; i++)
        {
            var obj = Instantiate(cloneObject);
            obj.transform.SetParent(transform);
            obj.name = obj.name.Replace("(Clone)", "");
            Put(obj);
        }

    }


    public void PutAll()
    {
        for (int i = 0; i < transform.childCount; i++)
        {
            var obj = transform.GetChild(i).gameObject;
            if (obj.activeSelf) Put(obj);
        }
    }

    //放入对象池中的对象
    public void Put(GameObject obj)
    {
        if (obj == null)
        {
            return;
        }
        obj.GetComponent<IPoolRecycle>()?.OnRecyclePut();
        obj.SetActive(false);

        if (obj.transform != transform)
        {
            obj.transform.SetParent(transform);//回收设置为此对象内部
        }

        if (stack.Contains(obj) == false)
        {
            stack.Push(obj);
        }

        cacheCount = transform.childCount;
    }

    //延迟执行put
    public void Put(GameObject obj, float time)
    {
        StartCoroutine(PutDelay(obj, time));
    }

    private IEnumerator PutDelay(GameObject obj, float time)
    {
        yield return new WaitForSeconds(time);
        Put(obj);
    }


    //获得对象池中的对象
    public GameObject Get()
    {
        GameObject obj;
        if (stack.Count <= 0)
        {
            obj = Instantiate(cloneObject);
            //print("对象池余量扩容");
        }
        else
        {
            obj = stack.Pop() as GameObject;
        }
        obj.SetActive(true);
        obj.transform.SetParent(transform);
        //重设默认值
        obj.transform.localScale = cloneObject.transform.localScale;
        obj.transform.rotation = cloneObject.transform.rotation;
        obj.transform.position = cloneObject.transform.position;

        obj.GetComponent<IPoolRecycle>()?.OnRecycleGet();

        return obj;
    }

    public void ClearAll()
    {
        stack.Clear();
        int childCount = transform.childCount;
        for (int i = 0; i < childCount; i++)
        {
            var obj = transform.GetChild(i).gameObject;
            if (obj != this.cloneObject)
            {
                DOTween.Kill(obj.GetInstanceID());
                GameObject.Destroy(obj);
            }
        }
    }

    /// <summary>
    /// 填充一个对象的子对象到达最大需求值,注意填充的时机，如果在填充后立刻获取childCount 数量还是当前的
    /// </summary>
    /// <param name="layout"></param>
    /// <param name="maxCount"></param>
    public void FillChild(Transform layout, int maxCount)
    {
        int total = maxCount;
        if (layout == null)
        {
            Debug.LogError("Need set a prefab Gameobject for layout:" + layout.name);
            return;
        }

        int offset = total - layout.childCount;

        // Debug.Log("距离目标差距:  目标是" + maxCount + " 当前有" + layout.childCount);

        if (offset >= 0)
        {
            for (int i = 0; i < offset; i++)
            {
                var obj = this.Get();
                obj.name = obj.name.Replace("(Clone)", "");
                obj.transform.SetParent(layout, false);
            }
        }
        else
        {
            for (int i = 0; i < layout.childCount; i++)
            {
                var obj = layout.GetChild(i).gameObject;
                if (i >= total)
                {
                    obj.SetActive(false);
                    obj.transform.SetParent(null);
                    this.Put(obj);
                    i--;//因为移除了对象，所以减少1
                }

            }

        }

    }

    private void OnDestroy()
    {

        foreach (GameObject go in stack)
        {
            DOTween.Kill(go.GetInstanceID());
        }
        stack.Clear();
    }

}
